/*
 Copyright (C) 1996-1997 GX Media, Inc.

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 */

#include "stdafx.h"
#include "HalfLife.h"
#include "Entity.h"
#include "Texture.h"
#include "LCommon.h"
#include "QDraw.h"

HalfLife::HalfLife(void) :
	Game(GetNumUtils())
{
	gameName = wxT("Half-Life");
	palDef = wxT("");
	defTexture = wxT("c1a0_w2");
	texExt = wxT("");
	specifyWads = true;

	cfg = new LConfig(gameName);

	QDraw::OutputText(_("Loading %s settings... "), gameName.c_str());

	gameDir = wxT("");
	cfg->RegisterVar(wxT("GameDir"), &gameDir, LVAR_WXSTR);

	setPIndex = 0;
	cfg->RegisterVar(wxT("SetParamIndex"), &setPIndex, LVAR_INT);

	runUtilsFlag = 0x0001;
	cfg->RegisterVar(wxT("RunUtils"), &runUtilsFlag, LVAR_INT);

	// HL QCSG
	utilsPath.resize(5);
	utilsParams.resize(5);
	utilsPath[0].Printf(wxT("%s/bin/hlqcsg.exe"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath1"), &utilsPath[0], LVAR_WXSTR);

	utilsParams[0] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam1"), &utilsParams[0], LVAR_WXSTR);

	// HL QBSP2
	utilsPath[1].Printf(wxT("%s/bin/hlqbsp2.exe"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath2"), &utilsPath[1], LVAR_WXSTR);

	utilsParams[1] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam2"), &utilsParams[1], LVAR_WXSTR);

	// HL VIS
	utilsPath[2].Printf(wxT("%s/bin/hlvis.exe"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath3"), &utilsPath[2], LVAR_WXSTR);

	utilsParams[2] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam3"), &utilsParams[2], LVAR_WXSTR);

	// HL QRAD
	utilsPath[3].Printf(wxT("%s/bin/hlqrad.exe"), LFile::GetInitDir().c_str());
	cfg->RegisterVar(wxT("UtilPath4"), &utilsPath[3], LVAR_WXSTR);

	utilsParams[3] = wxT("%file%");
	cfg->RegisterVar(wxT("UtilParam4"), &utilsParams[3], LVAR_WXSTR);

	// Half Life
	utilsPath[4] = wxT("hl.exe");
	cfg->RegisterVar(wxT("GamePath"), &utilsPath[4], LVAR_WXSTR);

	utilsParams[4] = wxT("-console -dev +map %file%");
	cfg->RegisterVar(wxT("GameParam"), &utilsParams[4], LVAR_WXSTR);

	QDraw::OutputText(_("OK.\n"));
}

HalfLife::~HalfLife(void)
{
	cfg->SaveVars();
	delete cfg;
}

bool HalfLife::Init(void)
{
	if (initialized)
		return true;

	if (gameDir.empty() || !LFile::ExistDir(gameDir))
	{
		wxDirDialog dirDialog(NULL, _("Locate Half-Life Folder"));

		if (dirDialog.ShowModal() != wxID_OK)
			return false;

		gameDir = dirDialog.GetPath();
	}

	baseDir.Printf(wxT("%s/valve"), gameDir.c_str());
	mapDir.Printf(wxT("%s/maps"), baseDir.c_str());

	texDB = new TexDB(this);
	texDir = baseDir;

	wxString wadFile;
	wadFile.Printf(wxT("%s/halflife.wad"), texDir.c_str());
	texDB->AddTexDir(wadFile);
	wadFile.Printf(wxT("%s/xeno.wad"), texDir.c_str());
	texDB->AddTexDir(wadFile);

	initialized = true;

	wxString pak0File;
	pak0File.Printf(wxT("%s/pak0.pak"), baseDir.c_str());

	LFile::UseDir(baseDir);
	pak0 = LFile::UsePak(pak0File);

	// Verify game exe.
	if (!LFile::Exist(utilsPath[GetNumUtils() - 1]))
		utilsPath[GetNumUtils() - 1].Printf(wxT("%s/hl.exe"), gameDir.c_str());

	return true;
}

WireFrameGeom *
HalfLife::LoadModel(const wxString &filename)
{
	return NULL;
}

bool HalfLife::LoadTexture(Texture *texture, const wxString &filename,
		int offset)
{
	texture_header_t header;
	int size, size2;
	int i;

	LFile file;
	QDraw::OutputText(_("Loading texture: %s... "), texture->GetName().c_str());
	if (!file.Open(filename))
	{
		QDraw::OutputText(_("Error. Couldn't open file.\n"));
		return false;
	}

	file.Seek(offset);
	file.Read(&header, sizeof(header), 1);

	if (header.width <= 0 || header.width > 1024)
	{
		QDraw::OutputText(_("Error. The texture width is erroneous.\n"), filename.c_str());
		return false;
	}
	if (header.height <= 0 || header.height > 1024)
	{
		QDraw::OutputText(_("Error. The texture height is erroneous.\n"), filename.c_str());
		return false;
	}

	size = header.width * header.height;
	size2 = size * 2;

	unsigned char *mip[4];
	short palCount;
	struct
	{
		unsigned char r, g, b;
	} pal[256];

	texture->mips = 4;

	mip[0] = (unsigned char *) malloc(size);
	mip[1] = (unsigned char *) malloc(size / 4);
	mip[2] = (unsigned char *) malloc(size / 16);
	mip[3] = (unsigned char *) malloc(size / 64);

	file.Seek(offset + header.mip1);
	file.Read(mip[0], size, 1);
	file.Seek(offset + header.mip2);
	file.Read(mip[1], size / 4, 1);
	file.Seek(offset + header.mip3);
	file.Read(mip[2], size / 16, 1);
	file.Seek(offset + header.mip4);
	file.Read(mip[3], size / 64, 1);

	file.Read(&palCount, sizeof(palCount));
	file.Read(pal, 768);

	unsigned short pal565[256];
	for (i = 0; i < 256; i++)
	{
		int r, g, b;

		r = pal[i].r;
		g = pal[i].g;
		b = pal[i].b;

		LPalette::GammaCorrect(r, g, b, QDraw::textureGamma);

		pal565[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
	}

	texture->mip[0] = malloc(size2);
	texture->mip[1] = malloc(size2 / 4);
	texture->mip[2] = malloc(size2 / 16);
	texture->mip[3] = malloc(size2 / 64);

	unsigned char *src;
	unsigned short *dst;

	for (int m = 0; m < 4; m++)
	{
		src = mip[m];
		dst = (unsigned short *) texture->mip[m];
		for (i = 0; i < size / (1 << (m * 2)); i++)
			*dst++ = pal565[*src++];
	}

	free(mip[0]);
	free(mip[1]);
	free(mip[2]);
	free(mip[3]);

	texture->surface = texture->mip[0];

	texture->realWidth = header.width;
	texture->realHeight = header.height;
	texture->bits = 16;

	QDraw::OutputText(_("OK.\n"));
	return true;
}

void HalfLife::ExtractTextures(void)
{
	/*
	 char wadFile[256];
	 char wadDir[256];
	 sprintf(wadDir, "%s\\wads", LFile::GetInitDir());
	 sprintf(wadFile, "%s\\Quake.wad", wadDir);

	 if(LFile::Exist(wadFile))
	 return;

	 if(MessageBox(NULL, "Extract Quake Textures?",
	 AfxGetAppName(), MB_YESNO) == IDNO)
	 return;

	 if(!LFile::ExistDir(wadDir))
	 _mkdir(wadDir);

	 CProgressFunc progFunc("Extracting");
	 paks2wad(baseDir, wadFile, CProgressFunc::SetPos);
	 */
}

// Game Map Compile Stuff.
const wxString &HalfLife::GetUtilName(int index) const
{
	static wxString utilNames[] =
	{ wxT("QCSG"), wxT("QBsp2"), wxT("Vis"), wxT("QRad"), wxT("Half-Life") };

	ASSERT(index >= 0 && index < 5);
	return utilNames[index];
}

//===== Leak file =====

wxString HalfLife::GetLeakFile(const wxString &docName) const
{
	ASSERT(!docName.empty());

	if (!LFile::ExistDir(mapDir))
		return wxEmptyString;

	return wxString::Format(wxT("%s/%s.lin"), mapDir.c_str(), docName.c_str());
}

Object *HalfLife::LoadLeakFile(const wxString &docName) const
{
	LFile leakFile;
	QDraw::OutputText(_("Loading leak information: %s... "), GetLeakFile(docName).c_str());

	if (!leakFile.Open(GetLeakFile(docName)))
	{
		QDraw::OutputText(_("Error.\nThere's no leak file.\n"));
		return NULL;
	}

	char *inLine;
	float x, y, z;
	Vector3d v1, v2;
	Vector3d posVec;

	// Read the first point.
	while (!leakFile.EndOfFile())
	{
		if ((inLine = leakFile.GetNextLine()) != NULL && sscanf(inLine,
				"%f %f %f", &x, &y, &z) == 3)
		{
			v1.NewVector(x, y, z);
			break;
		}
	}

	Object *rtnVal = new Object;
	Object *pNewSeg;
	Geometry *pSegBrush;

	// Read the rest.
	while (!leakFile.EndOfFile())
	{
		if ((inLine = leakFile.GetNextLine()) != NULL && sscanf(inLine,
				"%f %f %f", &x, &y, &z) == 3)
		{
			v2.NewVector(x, y, z);
			pSegBrush = Geometry::MakeSegment(v1, v2);
			pSegBrush->CenterGeometry(posVec);
			pNewSeg = new Object;
			pNewSeg->SetBrush(pSegBrush);
			pNewSeg->SetPosition(posVec);
			rtnVal->AddChild(*pNewSeg, false);
			v1 = v2;
		}
	}

	if (rtnVal->GetNumChildren() == 0)
	{
		delete rtnVal;
		rtnVal = NULL;
	}
	else
	{
		rtnVal->SetBoundRadius();
	}

	QDraw::OutputText(_("OK.\n"));
	return rtnVal;
}
